using Microsoft.Extensions.Logging;

namespace AuthService.Infrastructure.Services;

/// <summary>
/// 服务发现客户端接口
/// </summary>
public interface IServiceDiscoveryClient
{
    /// <summary>
    /// 获取服务URL
    /// </summary>
    /// <param name="serviceName">服务名称</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>服务URL</returns>
    Task<string?> GetServiceUrlAsync(string serviceName, CancellationToken cancellationToken = default);

    /// <summary>
    /// 获取所有服务实例URL
    /// </summary>
    /// <param name="serviceName">服务名称</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>服务URL列表</returns>
    Task<IEnumerable<string>> GetServiceUrlsAsync(string serviceName, CancellationToken cancellationToken = default);

    /// <summary>
    /// 检查服务是否可用
    /// </summary>
    /// <param name="serviceName">服务名称</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>是否可用</returns>
    Task<bool> IsServiceAvailableAsync(string serviceName, CancellationToken cancellationToken = default);
}

/// <summary>
/// 基于Consul的服务发现客户端
/// </summary>
public class ConsulServiceDiscoveryClient : IServiceDiscoveryClient
{
    private readonly IConsulServiceRegistry _consulServiceRegistry;
    private readonly ILogger<ConsulServiceDiscoveryClient> _logger;
    private readonly Random _random = new();

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="consulServiceRegistry">Consul服务注册</param>
    /// <param name="logger">日志记录器</param>
    public ConsulServiceDiscoveryClient(IConsulServiceRegistry consulServiceRegistry, ILogger<ConsulServiceDiscoveryClient> logger)
    {
        _consulServiceRegistry = consulServiceRegistry;
        _logger = logger;
    }

    /// <summary>
    /// 获取服务URL（负载均衡）
    /// </summary>
    public async Task<string?> GetServiceUrlAsync(string serviceName, CancellationToken cancellationToken = default)
    {
        try
        {
            var instances = await _consulServiceRegistry.GetHealthyServiceInstancesAsync(serviceName, cancellationToken);
            var instanceList = instances.ToList();

            if (!instanceList.Any())
            {
                _logger.LogWarning("未找到可用的服务实例: {ServiceName}", serviceName);
                return null;
            }

            // 简单的随机负载均衡
            var selectedInstance = instanceList[_random.Next(instanceList.Count)];
            var url = selectedInstance.Url;

            _logger.LogDebug("选择服务实例: {ServiceName} -> {Url}", serviceName, url);
            return url;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取服务URL失败: {ServiceName}", serviceName);
            return null;
        }
    }

    /// <summary>
    /// 获取所有服务实例URL
    /// </summary>
    public async Task<IEnumerable<string>> GetServiceUrlsAsync(string serviceName, CancellationToken cancellationToken = default)
    {
        try
        {
            var instances = await _consulServiceRegistry.GetHealthyServiceInstancesAsync(serviceName, cancellationToken);
            var urls = instances.Select(instance => instance.Url).ToList();

            _logger.LogDebug("获取到 {Count} 个服务实例: {ServiceName}", urls.Count, serviceName);
            return urls;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取服务URL列表失败: {ServiceName}", serviceName);
            return Enumerable.Empty<string>();
        }
    }

    /// <summary>
    /// 检查服务是否可用
    /// </summary>
    public async Task<bool> IsServiceAvailableAsync(string serviceName, CancellationToken cancellationToken = default)
    {
        try
        {
            var instances = await _consulServiceRegistry.GetHealthyServiceInstancesAsync(serviceName, cancellationToken);
            var isAvailable = instances.Any();

            _logger.LogDebug("服务可用性检查: {ServiceName} -> {IsAvailable}", serviceName, isAvailable);
            return isAvailable;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "检查服务可用性失败: {ServiceName}", serviceName);
            return false;
        }
    }
}

/// <summary>
/// 负载均衡策略枚举
/// </summary>
public enum LoadBalancingStrategy
{
    /// <summary>
    /// 随机选择
    /// </summary>
    Random,

    /// <summary>
    /// 轮询
    /// </summary>
    RoundRobin,

    /// <summary>
    /// 最少连接
    /// </summary>
    LeastConnections,

    /// <summary>
    /// 加权随机
    /// </summary>
    WeightedRandom
}

/// <summary>
/// 高级服务发现客户端
/// 支持多种负载均衡策略
/// </summary>
public class AdvancedServiceDiscoveryClient : IServiceDiscoveryClient
{
    private readonly IConsulServiceRegistry _consulServiceRegistry;
    private readonly ILogger<AdvancedServiceDiscoveryClient> _logger;
    private readonly LoadBalancingStrategy _loadBalancingStrategy;
    private readonly Dictionary<string, int> _roundRobinCounters = new();
    private readonly Random _random = new();

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="consulServiceRegistry">Consul服务注册</param>
    /// <param name="logger">日志记录器</param>
    /// <param name="loadBalancingStrategy">负载均衡策略</param>
    public AdvancedServiceDiscoveryClient(
        IConsulServiceRegistry consulServiceRegistry, 
        ILogger<AdvancedServiceDiscoveryClient> logger,
        LoadBalancingStrategy loadBalancingStrategy = LoadBalancingStrategy.Random)
    {
        _consulServiceRegistry = consulServiceRegistry;
        _logger = logger;
        _loadBalancingStrategy = loadBalancingStrategy;
    }

    /// <summary>
    /// 获取服务URL（使用配置的负载均衡策略）
    /// </summary>
    public async Task<string?> GetServiceUrlAsync(string serviceName, CancellationToken cancellationToken = default)
    {
        try
        {
            var instances = await _consulServiceRegistry.GetHealthyServiceInstancesAsync(serviceName, cancellationToken);
            var instanceList = instances.ToList();

            if (!instanceList.Any())
            {
                _logger.LogWarning("未找到可用的服务实例: {ServiceName}", serviceName);
                return null;
            }

            var selectedInstance = _loadBalancingStrategy switch
            {
                LoadBalancingStrategy.Random => SelectRandomInstance(instanceList),
                LoadBalancingStrategy.RoundRobin => SelectRoundRobinInstance(serviceName, instanceList),
                LoadBalancingStrategy.LeastConnections => SelectLeastConnectionsInstance(instanceList),
                LoadBalancingStrategy.WeightedRandom => SelectWeightedRandomInstance(instanceList),
                _ => SelectRandomInstance(instanceList)
            };

            var url = selectedInstance.Url;
            _logger.LogDebug("选择服务实例 ({Strategy}): {ServiceName} -> {Url}", 
                _loadBalancingStrategy, serviceName, url);
            
            return url;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取服务URL失败: {ServiceName}", serviceName);
            return null;
        }
    }

    /// <summary>
    /// 获取所有服务实例URL
    /// </summary>
    public async Task<IEnumerable<string>> GetServiceUrlsAsync(string serviceName, CancellationToken cancellationToken = default)
    {
        try
        {
            var instances = await _consulServiceRegistry.GetHealthyServiceInstancesAsync(serviceName, cancellationToken);
            var urls = instances.Select(instance => instance.Url).ToList();

            _logger.LogDebug("获取到 {Count} 个服务实例: {ServiceName}", urls.Count, serviceName);
            return urls;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取服务URL列表失败: {ServiceName}", serviceName);
            return Enumerable.Empty<string>();
        }
    }

    /// <summary>
    /// 检查服务是否可用
    /// </summary>
    public async Task<bool> IsServiceAvailableAsync(string serviceName, CancellationToken cancellationToken = default)
    {
        try
        {
            var instances = await _consulServiceRegistry.GetHealthyServiceInstancesAsync(serviceName, cancellationToken);
            var isAvailable = instances.Any();

            _logger.LogDebug("服务可用性检查: {ServiceName} -> {IsAvailable}", serviceName, isAvailable);
            return isAvailable;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "检查服务可用性失败: {ServiceName}", serviceName);
            return false;
        }
    }

    /// <summary>
    /// 随机选择实例
    /// </summary>
    private ServiceInstance SelectRandomInstance(List<ServiceInstance> instances)
    {
        return instances[_random.Next(instances.Count)];
    }

    /// <summary>
    /// 轮询选择实例
    /// </summary>
    private ServiceInstance SelectRoundRobinInstance(string serviceName, List<ServiceInstance> instances)
    {
        if (!_roundRobinCounters.ContainsKey(serviceName))
        {
            _roundRobinCounters[serviceName] = 0;
        }

        var index = _roundRobinCounters[serviceName] % instances.Count;
        _roundRobinCounters[serviceName]++;

        return instances[index];
    }

    /// <summary>
    /// 选择最少连接的实例（简化实现，实际应该跟踪连接数）
    /// </summary>
    private ServiceInstance SelectLeastConnectionsInstance(List<ServiceInstance> instances)
    {
        // 简化实现，实际应该跟踪每个实例的连接数
        return instances[_random.Next(instances.Count)];
    }

    /// <summary>
    /// 加权随机选择实例（基于标签权重）
    /// </summary>
    private ServiceInstance SelectWeightedRandomInstance(List<ServiceInstance> instances)
    {
        // 简化实现，可以基于实例的标签或元数据来设置权重
        var weights = instances.Select(instance =>
        {
            // 尝试从标签中获取权重，默认为1
            var weightTag = instance.Tags.FirstOrDefault(tag => tag.StartsWith("weight="));
            if (weightTag != null && int.TryParse(weightTag.Split('=')[1], out var weight))
            {
                return weight;
            }
            return 1;
        }).ToList();

        var totalWeight = weights.Sum();
        var randomValue = _random.Next(totalWeight);
        var currentWeight = 0;

        for (int i = 0; i < instances.Count; i++)
        {
            currentWeight += weights[i];
            if (randomValue < currentWeight)
            {
                return instances[i];
            }
        }

        return instances.Last();
    }
}
